#include "GLProgram.h"
#include <string>
#include <fstream>

using namespace std;

GLProgram::GLProgram(std::string userName)
	: userName(userName)
{
	name = glCreateProgram();
}

GLProgram::~GLProgram()
{
	glDeleteProgram(name);
	for (auto shader : _ownedShaders)
		delete shader;
}

void GLProgram::attach(GLShader* shader)
{
	glAttachShader(name, shader->name);
	_referencedShaders.push_back(shader);
}

void GLProgram::attach(GLenum shaderType, const std::string& file)
{
	GLShader* shader = new GLShader(shaderType, file);
	shader->compile();
	_ownedShaders.push_back(shader);
	glAttachShader(name, shader->name);
}

GLint GLProgram::getUniformLocation(const char* uniformName)
{
	return glGetUniformLocation(name, uniformName);
}

bool GLProgram::link()
{
	bool allCompiled=true;
	for (auto shader : _ownedShaders)
		if (!shader->compiled)
			allCompiled = false;
	for (auto shader : _referencedShaders)
		if (!shader->compiled)
			allCompiled = false;

	if (!allCompiled)
		return false;

	glLinkProgram(name);

	GLint status;
	glGetProgramiv(name, GL_LINK_STATUS, &status);

	GLint length;
	glGetProgramiv(name, GL_INFO_LOG_LENGTH, &length);

	bool ret=true;
	if (length > 1)
	{
		char* log = new char[length];
		glGetProgramInfoLog(name, length, NULL, log);

		fprintf(stdout, "Program %s: ", userName.c_str());
		if (status != GL_TRUE)
		{
			fprintf(stderr, "Linking failed!\n");
			ret = false;
		}
		else
			fprintf(stdout, "\n");

		fprintf(stderr, "%s", log);
		delete[] log;
	}

	/*if (ret == true)
	{
		const size_t MAX_SIZE = 10000;
		char binary[MAX_SIZE];
		GLenum format;
		GLint length;
		glGetProgramBinary(name,MAX_SIZE,&length,&format,&binary[0]);
		string a = string(userName).append(".txt");
		printf("%s\n",a.c_str());
		ofstream myfile;
		myfile.open (a.c_str(), ios::binary | ios::out);
		myfile.write(binary, length);
		myfile.close();
	}*/

	return ret;
}

void GLProgram::use()
{
	glUseProgram(name);
}